home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Format CD 41
/
Amiga Format CD41 (1999-06)(Future Publishing)(GB)[!][issue 1999-07].iso
/
-seriously_amiga-
/
cd-rom
/
acdb
/
src
/
acdb_cddb.e
< prev
next >
Wrap
Text File
|
1999-04-28
|
15KB
|
555 lines
OPT MODULE,OSVERSION=37
OPT PREPROCESS,REG=5
/*
*-- AutoRev header do NOT edit!!
*
* Project : ACDB (AMIGA CD Base) - program obsîugujâcy CDDB
* File : acdb_cddb.e
* Description : obsîuga CDDB via HTTP/GET
* Copyright : ©1999, Piotr Gapiïski
* Author : Piotr Gapiïski
* Creation Date : 20.03.99
* Current version : 1.0
* Translator : AmigaE v3.3a
*
*-- REVISION HISTORY
*
* 1.0 (20.03.99)
* o w przypadku inexact matches i multiple matches zapisywane sâ wszystkie
* istniejâce opisy pîyty przy czym pierwszy zapisywany jest z normalnâ
* nazwâ (CDID) a pozostaîe z koïcówkami bëdâcymi numerem kopii
* o w przypadku gdy bîëdów poîâczenia nie wpîywajâcych na ogólnâ pracë programu
* (takich jak np. brak ûâdanego opisu pîyty w bazie czy niewîaôciwy identyfikator pîyty0
* odpowiedni plik z katalogu TEMP zostanie zmieniony na IDxxxxxxxx.przyczyna_bîëdu
* o wsparcie dla arexx'a (w tym i dla zwrotnych kodów bîëdów)
*
* 0.5 (15.01.99)
* o zniesiony limit dîugoôci znaków w wierszu opisu (60 znaków)
* o nowy parser wiadomoôci odebranych
* o moûliwoôê przerwania odczytu danych co kaûde 100 bajtów
*
* 0.4 (03.01.99)
* o zwiëkszone bufory na komendy wysyîane do CDDB (do 400 bajtów)
* o identyfikator pîyty (cdid) MUSI byê 8 cyfrowy (z ewentualnymi zerami wiodâcymi)
* najprawdopodobniej to byîo przyczynâ 'zawieszania' sië programu
*
* 0.3 (28.12.98)
* o nowy parser wiadomoôci odebranych
* o obsîuga 'inexact matches'
* o protokóî zgodny z wersjâ 4 (obsîuga kodów QUERY: 211 i 210)
* o zapisywanie plików jest teraz zgodne z SCDP
*
* 0.2 (26.12.98)
* o progresywne odczytywanie danych nadchodzâcych z serwera
* odczytywanie trwa tak dîugo, aû Recv() zwróci 0 pobranych bajtów
* o poîâczenia sâ tylu KEEPALIVE dziëki czemu pomiëdzy poszczególnymi wywoîaniami
* Send() poîâczenie nie jest koïczone
* o tytuî pîyty (satandardowo w postaci TYTUÎ/AUTOR) jest teraz rozbity na dwie linie
*
* 0.1 (22.12.98)
* o pierwsza wersja (BETA)
* na podstawie @(#)cddb.howto 1.27 (98/12/09)
*
*-- REV_END --*
*/
MODULE 'tools/easygui'
MODULE 'intuition/intuition','intuition/screens','exec/nodes','exec/lists','dos/dos'
MODULE 'utility/tagitem','libraries/gadtools','bsdsocket','icon','tools/file','amigalib/lists'
MODULE 'afc/parser','afc/explain_exception'
MODULE '*acdb_debug','*acdb_cd','*acdb_net','*acdb_gui', '*acdb_arexx'
#ifdef DEBUG
MODULE 'tools/debug'
#define D(a,b) kputfmt(a,b)
#endif
#ifndef DEBUG
#define D(a,b)
#endif
#define CLIENTINFO 'narg+polbox.com+acdb+1.0&proto=4'
CONST BUFFSIZE = 10240
OBJECT match OF ln
category :PTR TO CHAR ->- kategoria pîyty
cdid :LONG ->- identyfikator
ENDOBJECT
EXPORT DEF tt_disks, tt_temp, tt_cddbhost, tt_cddbport,
tt_cdtime, tt_tracktime
EXPORT PROC cddb(cd:PTR TO cdinfo, arexx=NIL:PTR TO arxArgs) HANDLE
->-
->- procedura pobierajâca z CDDB opis ûâdanej pîyty kompaktowej
->- 1. jeûeli opis istnieje, zostanie zapisany w katalogu DISKS, a odpowiedni
->- plik z katalogu TEMP zostanie skasowany
->- 2. jeûeli opis nie istnieje to plik z katalogu TEMP zostanie zmieniony na
->- if.not_found
->- procedura zwraca TRUE/FALSE
->-
DEF matches:lh, match:PTR TO match, code, rc, error=NIL
DEF i
newList(matches)
D('[CDDB] querying database\n', NIL)
rc, code := query(cd, matches)
IF (rc)
->-
->- przejdú do pobierania pîytki
->-
i := 0
WHILE (match := RemHead(matches))
->-
->- pobieranie wszystkich moûliwych opisów pîytek
->- zwolnij niepotrzebne juû zasoby
->-
D('[CDDB] search cddb for \s\n', [match.name, NIL])
rc, code := description(cd, i++, match)
IF (match) THEN freematch(match)
EXIT (rc = FALSE)
ENDWHILE
ENDIF
IF (rc = FALSE)
SELECT code
->-
->- obsîuga bîëdów
->- czëôê z nich powoduje zmianë nazwy pliku CDID w katalogu TEMP
->-
CASE 202; renametemp(cd, '.not found')
CASE 401; renametemp(cd, '.not found')
CASE 403; renametemp(cd, '.corrupt')
CASE 501; renametemp(cd, '.invalid')
CASE 402; error := 'CDDB server error (402)!\nPlease use other CDDB host'
CASE 403; error := 'CDDB database entry is corrupt!\nPlease try again later'
CASE 409; error := 'CDDB no handshake!\nPlease try again later'
CASE 500; error := 'Command syntax error!\nSubmited command is corrupt, please\ncontact with ACDB author'
DEFAULT
->-
->- rozróûnienie bîëdów generowanych na podstawie kodu zwrotnego CDDB
->- a tych generowanych wewnâtrz procedury odbioru
->-
error := IF (code > 200)AND(code < 600) THEN 'General CDDB error!\nPlease use other CDDB server' ELSE code
ENDSELECT
IF (error) THEN Raise(error)
ENDIF
RETURN TRUE
EXCEPT
freeallmatches(matches)
IF (exception)
D('[CDDB] error \s\n', [exception, NIL])
IF (arexx)
->-
->- procedura zostaîa wywoîana z poziomu arexx'a wiëc wszelkie komunikaty
->- o bîëdach wîaônie tam bëdâ przekazane
->-
arexx.err := exception
arexx.rclong := 0
ELSE
->-
->- domyôlnie bëdzie wyôwietlony requester
->-
guiInformUser(exception, NIL, exceptioninfo)
ENDIF
ENDIF
ENDPROC FALSE
EXPORT PROC renametemp(cd, suffix)
->-
->- procedura zamieniajâca nazwë wybranego pliku cdid (z katalogu TEMP)
->- przez dodanie koïcówki suffix
->- zwraca kod bîëdów procedury DOS/Rename
->-
DEF in[255]:STRING, out[255]:STRING
StrCopy(in, tt_temp)
AddPart(in, cdFileId(cd), 255)
StrCopy(out, in)
StrAdd(out, suffix)
ENDPROC Rename(in, out)
->-
->- prywatne
->- procedury wspomagajâce pobieranie opisów pîyt z internetu
->-
PROC query(cd, matches:PTR TO lh) HANDLE
->-
->- zapytanie o kategorie pîyty
->- zwraca 1: TRUE/FALSE, 2: kod CDDB/kod bîëdu
->- w przypadku sukcesu bëdzie to TRUE/CDDB a w przypadku poraûki FALSE/CDDB lub
->- FALSE/ERROR
->-
DEF sd, cmd[400]:STRING, tmp[400]:STRING, tracks
DEF buff:PTR TO CHAR, bytes, code, x, rc=FALSE
->-
->- budowanie zapytania
->-
buff := New(BUFFSIZE)
D('[QUERY] connect to \s:\d\n', [tt_cddbhost, tt_cddbport, NIL])
IF (sd := netConnect(tt_cddbhost, tt_cddbport))<0 THEN Raise('Cannot resolve (cddb) host address!\nIncorrect address or TCP/IP stack not running')
D('[QUERY] compute cddb query\n', NIL)
tracks := cdTracks(cd)
stringFmt(tmp, '/~cddb/cddb.cgi?cmd=cddb+query+%08.8lx+%ld', [cdId(cd), tracks, NIL])
StrCopy(cmd, tmp)
FOR x := 0 TO (tracks - 1) DO StrAdd(cmd, stringFmt(tmp, '+%ld', [cdTrackOffset(cd, x), NIL]))
stringFmt(tmp, '+%ld&hello=%s', [cdTime(cd), CLIENTINFO, NIL])
StrAdd(cmd, tmp)
->-
->- wysyîanie zapytania do bazy danych
->-
D('[QUERY] sending query\n', NIL)
IF netSendcmd(sd, cmd)=FALSE THEN Raise('Connection broken!\nPlease try again later')
bytes := netReceive(sd, buff, BUFFSIZE)
IF (bytes = 0) THEN Raise('Cannot read data from host\nAborted due to user request')
->-
->- tworzenie listy wszystkich opisów pîytek pasujâcych do wzorca
->-
code := Val(buff)
rc := findmatches(matches, buff, bytes)
D('[QUERY] code \d\n', [code, NIL])
D('[QUERY] matches \s FOUND\n', [IF (rc) THEN '' ELSE 'NOT', NIL])
EXCEPT DO
IF (buff) THEN Dispose(buff)
IF (sd >= 0) THEN CloseSocket(sd)
IF (exception)
rc := FALSE
code := exception
D('[QUERY] error \s\n', [exception, NIL])
ENDIF
ENDPROC rc, code
PROC description(cd, copy, match:PTR TO match) HANDLE
->-
->- zapytanie o opis pîyty okreôlonej przez cd oraz strukturë match
->- zwraca 1: TRUE/FALSE, 2: kod CDDB/kod bîëdu
->- w przypadku sukcesu bëdzie to TRUE/CDDB a w przypadku poraûki FALSE/CDDB lub
->- FALSE/ERROR
->-
DEF cmd[400]:STRING
DEF sd, buff:PTR TO CHAR, code, bytes, rc=FALSE
buff := New(BUFFSIZE)
D('[DESCRIPTION] connect to \s:\d\n', [tt_cddbhost, tt_cddbport, NIL])
IF (sd := netConnect(tt_cddbhost, tt_cddbport))<0 THEN Raise('Cannot resolve (cddb) host address!\nIncorrect address or TCP/IP stack not running')
stringFmt(cmd, '/~cddb/cddb.cgi?cmd=cddb+read+%s+%08.8lx&hello=%s', [match.category, match.cdid, CLIENTINFO, NIL])
D('[DESCRIPTION] send cmd\n', NIL)
IF netSendcmd(sd, cmd)=FALSE THEN Raise('Connection broken!\nPlease try again later')
D('[DESCRIPTION] receive description\n', NIL)
bytes := netReceive(sd, buff, BUFFSIZE)
IF (bytes = 0) THEN Raise('Cannot read data from host\nAborted due to user request')
code := Val(buff)
D('[DESCRIPTION] code \d\n', code)
rc := IF (code = 210) THEN save(cd, copy, buff, bytes) ELSE FALSE
EXCEPT DO
IF (buff) THEN Dispose(buff)
IF (sd >= 0) THEN CloseSocket(sd)
IF (exception)
rc := FALSE
code := exception
D('[DESCRIPTION] error \s\n', [exception, NIL])
ENDIF
ENDPROC rc, code
PROC save(cd, copy, buff:PTR TO CHAR, bytes) HANDLE
->-
->- zapisywanie opisu pîytki na dysk w formacie SCDP
->- copy to kolejny numer kopii danego opisu pîyty ale jeûeli copy = 0
->- to suffix nie zostanie zapisany
->-
DEF list, listlen, path[255]:STRING
DEF title:PTR TO CHAR, x, tmp[400]:STRING
DEF pos, handle=NIL, mm, ss
list := stringsinfile(buff, bytes, countstrings(buff, bytes))
listlen := ListLen(list)
->-
->- okreôlnenie nazwy zapisywanego pliku w konwencji
->- ID.x
->- gdzie x to kolejny numer kopii
->-
StrCopy(tmp, tt_disks)
AddPart(tmp, cdFileId(cd), 255)
stringFmt(path, IF (copy > 0) THEN '%s.%ld' ELSE '%s', [tmp, copy, NIL])
D('[SAVE] file \s\n', [path, NIL])
IF (handle := Open(path, MODE_NEWFILE))=NIL THEN Raise('Cannot write CD description!\nCheck all TOOLTYPES passed to the program')
->-
->- zapis danych do pliku o nazwie NAME
->- tytuî pîyty trzeba przeksztaîciê z formatu "AUTOR / TYTUÎ" na "AUTOR\nTYTUÎ"
->-
IF (title := FindToolType(list, 'DTITLE'))
title[StrLen(title) - 1] := "\0"
->-
->- znajdú znak rozdzielajâcy
->-
IF (pos := InStr(title, '/'))
->-
->- podziel na tytuî i autora
->-
title[pos - 1] := "\0"
D('[SAVE] author \s\n', [title, NIL])
Write(handle, title, StrLen(title)); Write(handle, '\n', STRLEN)
IF (tt_cdtime)
->-
->- dodaj do opisu caîkowity czas trwania pîyty
->-
ss, mm := Mod(cdTime(cd), 60)
stringFmt(tmp, '%s [%ld:%02.2ld]\n', [(title + pos + 2), mm, ss, NIL])
ELSE
->-
->- tylko autor pîyty
->-
stringFmt(tmp, '%s\n', [(title + pos + 2), NIL])
ENDIF
D('[SAVE] album \s', [tmp, NIL])
Write(handle, tmp, StrLen(tmp))
ENDIF
ELSE
->-
->- bîâd, opis pîyty nie zawiera tytuîu
->- skasuj dopiero co otwarty plik
->-
Close(handle)
DeleteFile(path)
Raise('Corrupted CD description!\nAborted')
ENDIF
->-
->- pobierz tytuîy poszczególnych utworów
->-
FOR x := 0 TO (cdTracks(cd) - 1)
stringFmt(tmp, 'TTITLE%ld', [x, NIL])
title := FindToolType(list, tmp)
IF (title)
title[StrLen(title) -1] := "\0"
IF (tt_tracktime)
->-
->- dodaj do opisu caîkowity czas trwania pîyty
->-
ss, mm := Mod(cdTrackTime(cd, x), 60)
stringFmt(tmp, '%s [%ld:%02.2ld]\n', [title, mm, ss, NIL])
ELSE
->-
->- tylko track
->-
stringFmt(tmp, '%s\n', [title, NIL])
ENDIF
D('[SAVE] track #\d \s', [x, tmp, NIL])
Write(handle, tmp, StrLen(tmp))
ENDIF
ENDFOR
Close(handle)
RETURN TRUE
EXCEPT
IF (handle) THEN Close(handle)
D('[SAVE] error \s\n', [exception, NIL])
ENDPROC FALSE
PROC findmatches(matches:PTR TO lh, buff:PTR TO CHAR, bytes) HANDLE
->-
->- procedura wyciâgajâca informacje o identyfikatorach pîyty
->- z bofora odebranych danych
->-
DEF par=NIL:PTR TO parser, x, match=NIL: PTR TO match
DEF name:PTR TO CHAR, category:PTR TO CHAR, tmp[10]:STRING
DEF list:PTR TO LONG, listlen, rc=TRUE, code
code := Val(buff)
IF (code = 210)OR(code = 211)
->-
->- multiple matches lub inexact matches
->- zamieï na E-LIST
->- lista musi mieê przynajmniej 3 pozycje (nagîowek, min. 1 pozycja, kropka koïczâca bufor)
->-
list := stringsinfile(buff, bytes, countstrings(buff, bytes))
listlen := ListLen(list)
IF (listlen < 3) THEN RETURN FALSE
NEW par.parser()
->-
->- pobierz dane z bufora (categoria, identyfikator, tytuî)
->- pierwsza linia zawiera kod zwrotny, ostatnia zawiera kropkë - moûna je pominâê
->-
FOR x := 1 TO (listlen - 2)
par.parse('CAT,ID,NAME/F', ListItem(list, x))
category := par.arg(0)
name := par.arg(2)
StrCopy(tmp, '$')
StrAdd(tmp, par.arg(1))
->-
->- zainicjuj element listy
->-
NEW match
match.category := String(StrLen(category) + 10)
match.name := String(StrLen(name) + 10)
match.cdid := Val(tmp)
StrCopy(match.category, category)
StrCopy(match.name, name)
AddHead(matches, match)
D('[FINDMATCH] category \s, cdid $\h\n', [category, Val(tmp), NIL])
ENDFOR
ELSEIF (code = 200)
->-
->- match found
->- zdekoduj kategorie pîyty
->-
NEW par.parser()
par.parse('CODE,CAT,ID,NAME/F', buff)
category := par.arg(1)
name := par.arg(3)
StrCopy(tmp, '$')
StrAdd(tmp, par.arg(2))
->-
->- zainicjuj element listy
->-
NEW match
match.category := String(StrLen(category) + 10)
match.name := String(StrLen(name) + 10)
match.cdid := Val(tmp)
StrCopy(match.category, category)
StrCopy(match.name, name)
AddHead(matches, match)
D('[FINDMATCH] category \s, cdid $\h\n', [category, match.cdid, NIL])
ELSE
->-
->- bîâd odpowiedzi serwera
->-
rc := FALSE
ENDIF
EXCEPT DO
END par
ENDPROC rc
PROC freeallmatches(matches: PTR TO lh)
->-
->- zwalnia pamiëc zajëtâ przez caîâ listë
->- nie zwraca ûadnej wartoôci
->-
DEF match:PTR TO match
WHILE (match := RemHead(matches)) DO freematch(match)
ENDPROC
PROC freematch(match: PTR TO match)
->-
->- zwalnia pamiëc zajëtâ przez element listy
->- nie zwraca ûadnej wartoôci
->-
IF (match.category) THEN DisposeLink(match.category)
IF (match.name) THEN DisposeLink(match.name)
END match
ENDPROC